﻿using System;
using System.Collections.Generic;
using System.Text;

namespace BankTransfer.Bank.Application.Impl
{
    public class TransferServiceImpl : ITransferService
    {
        //事务脚本类的代码

        private const string TOPIC_AUDIT_LOG = "TOPIC_AUDIT_LOG";
        private readonly AccountMapper accountDAO;
        private readonly KafkaTemplate kafkaTemplate;
        private readonly YahooForexService yahooForex;

        public bool Transfer(long sourceUserId, string targetAccountNumber, decimal targetAmount, Currency targetCurrency)
        {
            // 1.从数据库读取数据，忽略所有校验逻辑如账号是否存在等
            AccountDO sourceAccountDO = accountDAO.SelectByUserId(sourceUserId);
            AccountDO targetAccountDO = accountDAO.SelectByAccountNumber(targetAccountNumber);

            // 2. 业务参数校验
            if (!targetAccountDO.GetCurrency().Equals(targetCurrency))
            {
                throw new InvalidCurrencyException();
            }

            // 3. 获取外部数据，并且包含一定的业务逻辑 exchange rate = 1 source currency = X target currency
            decimal exchangeRate = 1;
            if (sourceAccountDO.GetCurrency().Equals(targetCurrency))
            {
                exchangeRate = yahooForex.GetExchangeRate(sourceAccountDO.GetCurrency(), targetCurrency.ToString());
            }
            decimal sourceAmount = targetAmount * exchangeRate;

            // 4. 业务参数校验
            if (sourceAccountDO.GetAvailable().CompareTo(sourceAmount) < 0)
            {
                throw new InsufficientFundsException();
            }
            if (sourceAccountDO.GetDailyLimit().CompareTo(sourceAmount) < 0)
            {
                throw new DailyLimitExceededException();
            }

            // 5. 计算新值，并且更新字段
            decimal newSource = sourceAccountDO.GetAvailable() - sourceAmount;
            decimal newTarget = targetAccountDO.GetAvailable() + targetAmount;
            sourceAccountDO.SetAvailable(newSource);
            targetAccountDO.SetAvailable(newTarget);

            // 6. 更新到数据库
            accountDAO.Update(sourceAccountDO);
            accountDAO.Update(targetAccountDO);

            // 7. 发送审计消息
            string message = $"{sourceUserId},{targetAccountNumber},{targetAmount},{targetCurrency}";
            kafkaTemplate.Send(TOPIC_AUDIT_LOG, message);
            return true;
        }
    }
}
